package de.ssmp.wbs.logik;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map.Entry;

import de.ssmp.wbs.Utilities;
import de.ssmp.wbs.daten.Ergebnis;
import de.ssmp.wbs.daten.Torschuss;

/**
 * Diese Klasse beinhaltet den Versionsraummethoden-Algorithmus mit den
 * Funktionen des Generalisierens und Spezialisierens, sowie eine Methode die
 * beide vereint und ein Ergebnis zurückliefert
 * 
 * @author stiewen
 * @author maximilian
 * @version 1
 * 
 */
public class Versionsraummethode {

	/* Attributes / Variables */
	// Berechnung-Konfigurations-Parameter...
	private static final boolean NUR_EIN_ERGEBNIS = true;

	private static final boolean NUR_EIN_POSITIVES_BSP = true;

	private static final int NUR_X_NEGATIVE_BSP = 2;

	// Ausgabe-Konfigurations-Parameter
	private static final boolean ZEIGE_STERN_ALGORITHMUS_ERGEBNIS_ANZAHL = true;

	private static final boolean ZEIGE_STERN_ALGORITHMUS_NEGATIV_BSP_VERGLEICHE = true;

	/* Methods */
	/**
	 * Führt den Versionsraummethoden und AQ-Algorithmus durch.
	 * 
	 * @param torschuesse
	 *            Eine Liste aller Torschüsse eines Spielers.
	 * @return Eine Liste mit Ergebnissen aller Ziele und deren Situationen in
	 *         der ein Spieler auf ein Ziel schießt.
	 */
	public static ArrayList<Ergebnis> work(ArrayList<Torschuss> torschuesse) {
		ArrayList<Ergebnis> alErgebnisse = new ArrayList<Ergebnis>();

		// Suche alle Ziele, die existieren
		String strMglZiel = null;
		ArrayList<String> alZiele = new ArrayList<String>();
		System.out.println("Suche Ziele ...");

		for (Torschuss schussBeispiel : torschuesse) {
			strMglZiel = schussBeispiel.getAttributes().get(
					Utilities.ATTRIBUT_ZIEL);
			if (!alZiele.contains(strMglZiel)) {
				alZiele.add(strMglZiel);
				alErgebnisse.add(new Ergebnis(strMglZiel));

			}

		}

		// Starte AQ-Algorithmus
		System.out.println("Starte AQ-Algorithmus ...");
		// Positiv- und Negativ-Beispiellisten
		ArrayList<Torschuss> alPositivebeispiele = null;
		ArrayList<Torschuss> alNegativeBeispiele = null;

		for (Ergebnis ergebnis : alErgebnisse) {

			System.out.println("Berechne Ergebnis fuer Ziel: "
					+ ergebnis.getZiel());

			alPositivebeispiele = new ArrayList<Torschuss>();
			alNegativeBeispiele = new ArrayList<Torschuss>();
			// Bilde Menge von positiven und negativen Beispielen
			for (Torschuss torschuss : torschuesse) {
				if (ergebnis.getZiel().equalsIgnoreCase(
						torschuss.getAttributes().get(Utilities.ATTRIBUT_ZIEL)))
					// Wenn positives Beispiel fuer dieses Ziel
					alPositivebeispiele.add(torschuss);

				else
					// Wenn negatives Beispiel fuer dieses Ziel
					alNegativeBeispiele.add(torschuss);

			}

			// Wende den AQ-Algorithmus fuer dieses Ergebnis an.
			ergebnis.setUntereGrenze(algorithmusAQ(ergebnis,
					alPositivebeispiele, alNegativeBeispiele));

			// TODO: Erst einmal nur fuer ein ergebnis
			if (Versionsraummethode.NUR_EIN_ERGEBNIS)
				break;

		}

		// Berechne ergebnisse
		// System.out.println("Starte Varianzanalyse ...");
		// String strErgebnisZiel = null;
		// ArrayList<Torschuss> alG = null;
		// ArrayList<Torschuss> alS = null;
		// int ergebnisZaehler = 0;
		// for (Ergebnis ergebnis : alErgebnisse) {
		// ergebnisZaehler++;
		// strErgebnisZiel = ergebnis.getZiel();
		// alG = ergebnis.getObereGrenze();
		// alS = ergebnis.getUntereGrenze();
		// for (Torschuss schussBeispiel : torschuesse) {
		//
		// System.out.println(ergebnisZaehler + "_" + strErgebnisZiel
		// + ": Neues Beispiel");
		//
		// if (strErgebnisZiel.equalsIgnoreCase(schussBeispiel
		// .getAttributes().get(Utilities.ATTRIBUT_ZIEL))) {
		// System.out.println("\tPositiv Schritt 1");
		// Versionsraummethode.loescheAlleDieAusschliessen(
		// schussBeispiel, alG);
		//
		// System.out.println("\tPositiv Schritt 2");
		// Versionsraummethode
		// .ersetzeDurchSpeziellsteVerallgemeinerung(
		// schussBeispiel, alS);
		//
		// System.out.println("\tPositiv Schritt 3");
		// Versionsraummethode.StreicheAlleAllgemeineren(
		// schussBeispiel, alG, alS);
		//
		// } else {
		// System.out.println("\tNegativ Schritt 1");
		// Versionsraummethode.loescheAlleDieEinschliessen(
		// schussBeispiel, alS);
		//
		// System.out.println("\tNegativ Schritt 2");
		// Versionsraummethode
		// .ersetzeDurchAllgemeinsteSpezialisierung(
		// schussBeispiel, alG, alS);
		//
		// System.out.println("\tNegativ Schritt 3");
		// Versionsraummethode.streicheAlleSpezielleren(
		// schussBeispiel, alG, alS);
		//
		// }
		//
		// if (alG.size() == 0 || alS.size() == 0) {
		// System.out.println(ergebnisZaehler + "_" + strErgebnisZiel
		// + ": Beende Ergebnisberechnung: G.size() == "
		// + alG.size() + " - S.size() == " + alS.size());
		// break;
		// }
		//
		// }
		//
		// }

		return alErgebnisse;
	}

	/**
	 * Führt den AQ-Algorithmus durch.
	 * 
	 * @param ergebnis
	 *            Das Ergebnis - also um welches Ziel es sich handelt inklusive
	 *            der Situation in der der Spieler drauf schießt.
	 * @param alPositiv
	 *            Alle positiv Beispiele für das Ziel.
	 * @param alNegativ
	 *            Alle negativ Beispiele für das Ziel.
	 * @return Ein neues Ergebnis für die Torschuss-Situation das entsprechende
	 *         Ziel betreffend.
	 */
	private static ArrayList<Torschuss> algorithmusAQ(Ergebnis ergebnis,
			ArrayList<Torschuss> alPositiv, ArrayList<Torschuss> alNegativ) {
		ArrayList<Torschuss> alKonzepte = new ArrayList<Torschuss>();

		Torschuss positivesBeispiel = null;
		ArrayList<Torschuss> alSternErgebnis = null;
		Torschuss besteVerallgemeinerung = null;
		while (alPositiv.size() > 0) {
			// Hole ein positives Beispiel
			positivesBeispiel = alPositiv.get(0);
			alPositiv.remove(positivesBeispiel);

			// Berechne Stern aus dem positiven und allen negativen
			// BeispielenBSP
			alSternErgebnis = algorithmusStern(ergebnis, positivesBeispiel,
					alNegativ);

			// TODO: ZEIGE_STERN_ALGORITHMUS_ERGEBNIS_ANZAHL
			if (ZEIGE_STERN_ALGORITHMUS_ERGEBNIS_ANZAHL)
				System.out
						.println("Naechstes pos. Beispiel: Anzahl der Hypothesen durch Stern Algorithmus: "
								+ alSternErgebnis.size());

			// Waehle BESTE Verallgemeinerung: s
			besteVerallgemeinerung = waehleBesteVerallgemeinerung(alSternErgebnis);

			// Wenn ueberhaupt eine Verallgemeinerung existiert
			if (besteVerallgemeinerung != null) {
				// Nehme Verallgemeinerung s in Konzept auf
				alKonzepte.add(besteVerallgemeinerung);

				// Entferne alle positiven Beispiele, die durch s abgedeckt sind
				Versionsraummethode.streicheAlleSpezielleren(
						besteVerallgemeinerung, alPositiv);

			}

			// TODO: erst einmal nur ein positives Beispiel
			if (Versionsraummethode.NUR_EIN_POSITIVES_BSP)
				break;

		}

		return alKonzepte;

	}

	/**
	 * Führt den Stern Algorithmus aus.
	 * 
	 * @param ergebnis
	 *            Die Situation in der der Spieler auf das entsprechende Ziel
	 *            schießt.
	 * @param positivesBeispiel
	 *            Ein einziges positiv Beispiel
	 * @param alNegativeBeispiele
	 *            Alle negativ Beispiele
	 * @return Die Situation in der der Spieler auf das entsprechende Ziel
	 *         schießt.
	 */
	private static ArrayList<Torschuss> algorithmusStern(Ergebnis ergebnis,
			Torschuss positivesBeispiel,
			ArrayList<Torschuss> alNegativeBeispiele) {
		ArrayList<Torschuss> alG = new ArrayList<Torschuss>();

		// Erzeuge allgemeinste Form von Hypothese: Alle Attribute = '*'. Diese
		// Allgemeinste Form wird folgend spezialisiert.
		Torschuss allgemeineForm = new Torschuss();
		HashMap<String, String> hmAllgemeineAttribute = allgemeineForm
				.getAttributes();
		for (String strAttributName : Utilities.keys) {
			if (strAttributName == Utilities.ATTRIBUT_ZIEL)
				continue;

			hmAllgemeineAttribute.put(strAttributName, Utilities.STAR);

		}

		alG.add(allgemeineForm);

		// Gebe speziellste Verallgemeinerung fuer das eine positive Beispiel
		// und alle negativen Beispiele zurueck.
		ArrayList<Torschuss> alNeueMengen = null;
		ArrayList<Torschuss> alNeueTeilMengen = null;
		int negativBeispielCounter = 0;
		for (Torschuss negativBeispiel : alNegativeBeispiele) {
			negativBeispielCounter++;

			// TODO: erst mal nur die ersten beiden negativen beispiele
			if (negativBeispielCounter > Versionsraummethode.NUR_X_NEGATIVE_BSP)
				return alG;

			alNeueMengen = new ArrayList<Torschuss>();
			AllgemeineForm: for (int i = 0; i < alG.size();) {
				allgemeineForm = alG.get(i);

				for (Entry<String, String> attribut : allgemeineForm
						.getAttributes().entrySet()) {
					if (istZiel(attribut))
						continue;

					if (!negativBeispiel.getAttributes().get(attribut.getKey())
							.equalsIgnoreCase(attribut.getValue())
							&& attribut.getValue() != Utilities.STAR) {

						if (ZEIGE_STERN_ALGORITHMUS_NEGATIV_BSP_VERGLEICHE) {
							System.out.println("Bei negativem Bsp ("
									+ negativBeispielCounter + "/"
									+ alNegativeBeispiele.size() + "): "
									+ negativBeispiel);
							System.out.println("Habe betrachtet: "
									+ allgemeineForm);
							System.out
									.println("Muss nichts getan werden, wegen Attribut: "
											+ attribut.getKey());

						}

						i++;
						continue AllgemeineForm;

					}

				}

				// Wird nicht erreicht, wenn ein Attribut Literal aus
				// SchussBeispiel nicht dem Attribut Literal aus Torschuss
				// gleicht.
				alNeueTeilMengen = erzeugeSpeziellsteVerallgemeinerung(
						positivesBeispiel, allgemeineForm, negativBeispiel);

				alNeueMengen.addAll(alNeueTeilMengen);
				alG.remove(allgemeineForm);

				if (ZEIGE_STERN_ALGORITHMUS_NEGATIV_BSP_VERGLEICHE) {
					System.out.println("Bei negativem Bsp ("
							+ negativBeispielCounter + "/"
							+ alNegativeBeispiele.size() + "): "
							+ negativBeispiel);
					System.out.println("habe betrachtet: " + allgemeineForm);
					System.out.println("Ersetzt mit: " + alNeueTeilMengen);

				}

			}

			alG.addAll(alNeueMengen);
			System.out.println("Size of alG:" + alG.size());

		}

		return alG;

	}

	/**
	 * Eine Methode welche ein Ergebnis (Torschuss-Situation für Ziel x) aus der
	 * Ergebnismenge auswählt.
	 * 
	 * @param alSternErgebnisse
	 *            Alle Torschuss-Situationen die errechnet wurden für das Ziel x
	 * @return Eine einzige Torschussituation.
	 */
	private static Torschuss waehleBesteVerallgemeinerung(
			ArrayList<Torschuss> alSternErgebnisse) {

		if (alSternErgebnisse.size() > 0)
			return alSternErgebnisse.get(0);

		return null;

	}

	// # 1
	/**
	 * Geht alle Attribute zu jedem Torschuss durch. Wenn kein Attribut dem
	 * Attribut aus dem SchussBeispiel gleicht, wird der Torschuss aus der Menge
	 * G geloescht.
	 * 
	 * @param schussBeispiel
	 *            Ein Torschuss.
	 * @param alG
	 *            Menge an Torschüssen aus der der Torschuss eventuell hinterher
	 *            gelöscht ist.
	 */
	private static void loescheAlleDieAusschliessen(Torschuss schussBeispiel,
			ArrayList<Torschuss> alG) {
		/*
		 * Gehe alle Attribute zu jedem Torschuss durch. Wenn kein Attribut dem
		 * Attribut aus dem SchussBeispiel gleicht, wird der Torschuss aus der
		 * Menge G geloescht.
		 */

		Torschuss torschuss = null;
		String strSchussBeispielAttributWert = null;
		for (int i = 0; i < alG.size();) {
			torschuss = alG.get(i);
			for (Entry<String, String> attribut : torschuss.getAttributes()
					.entrySet()) {
				if (istZiel(attribut))
					continue;

				strSchussBeispielAttributWert = schussBeispiel.getAttributes()
						.get(attribut.getKey());
				if (!strSchussBeispielAttributWert.equalsIgnoreCase(attribut
						.getValue()) && attribut.getValue() != Utilities.STAR) {

					// System.out.println("Wegen " + schussBeispiel
					// + " entferne ich bei Attribut " + attribut.getKey()
					// + " - " + torschuss);
					alG.remove(torschuss);

				}

			}

			i++;

		}

	}

	// # 2
	/**
	 * Geht alle Attribute in allen Torschuessen in S durch. Wenn ein Torschuss
	 * das SchussBeispiel nicht einschliesst, wird es mit der speziellsten
	 * Verallgemeinerung ersetzt.
	 * TODO
	 * 
	 * @param schussBeispiel
	 * @param alS
	 */
	private static void ersetzeDurchSpeziellsteVerallgemeinerung(
			Torschuss schussBeispiel, ArrayList<Torschuss> alS) {
		/*
		 * Gehe alle Attribute in allen Torschuessen in S durch. Wenn ein
		 * Torschuss das SchussBeispiel nicht einschliesst, wird es mit der
		 * speziellsten Verallgemeinerung ersetzt.
		 */
		for (Torschuss torschuss : alS) {
			for (Entry<String, String> attribut : torschuss.getAttributes()
					.entrySet()) {
				if (istZiel(attribut))
					continue;

				if (!schussBeispiel.getAttributes().get(attribut.getKey())
						.equalsIgnoreCase(attribut.getValue())) {

					if (attribut.getValue() == Utilities.UNDERSCORE)
						attribut.setValue(schussBeispiel.getAttributes().get(
								attribut.getKey()));
					else
						attribut.setValue(Utilities.STAR);

				}

			}

		}

	}

	// # 3
	/**
	 * Geht alle Attribute zu jedem Torschuss durch. Wenn ein Attribut
	 * allgemeiner ist als das Attribut aus dem SchussBeispiel, wird der
	 * Torschuss aus der Menge S geloescht.
	 * TODO
	 * 
	 * @param schussBeispiel
	 * @param alG
	 * @param alS
	 */
	private static void StreicheAlleAllgemeineren(Torschuss schussBeispiel,
			ArrayList<Torschuss> alG, ArrayList<Torschuss> alS) {
		/*
		 * Gehe alle Attribute zu jedem Torschuss durch. Wenn ein Attribut
		 * allgemeiner ist als das Attribut aus dem SchussBeispiel, wird der
		 * Torschuss aus der Menge S geloescht.
		 */

		Torschuss torschussS = null;
		Torschuss: for (Torschuss torschussG : alG) {
			for (int i = 0; i < alS.size();) {
				torschussS = alS.get(i);
				for (Entry<String, String> attribut : torschussS
						.getAttributes().entrySet()) {
					if (istZiel(attribut))
						continue;

					if (torschussS.getAttributes().get(attribut.getKey()) == Utilities.STAR
							&& torschussG.getAttributes()
									.get(attribut.getKey()) != Utilities.STAR) {
						alS.remove(torschussS);
						continue Torschuss;

					}

				}

				i++;

			}

		}

	}

	// # 4
	/**
	 * Geht alle Attribute zu jedem Torschuss durch. Wenn ein Attribut dem
	 * Attribut aus dem SchussBeispiel gleicht, wird der Torschuss aus der Menge
	 * S geloescht.
	 * TODO
	 * 
	 * @param schussBeispiel
	 * @param alS
	 */
	private static void loescheAlleDieEinschliessen(Torschuss schussBeispiel,
			ArrayList<Torschuss> alS) {
		/*
		 * Gehe alle Attribute zu jedem Torschuss durch. Wenn ein Attribut dem
		 * Attribut aus dem SchussBeispiel gleicht, wird der Torschuss aus der
		 * Menge S geloescht.
		 */

		Torschuss torschuss = null;
		String strAttributeValue = null;
		Torschuss: for (int i = 0; i < alS.size();) {
			torschuss = alS.get(i);
			for (Entry<String, String> attribut : torschuss.getAttributes()
					.entrySet()) {
				if (istZiel(attribut))
					continue;

				strAttributeValue = schussBeispiel.getAttributes().get(
						attribut.getKey());
				if (!strAttributeValue.equalsIgnoreCase(attribut.getValue())
						&& strAttributeValue != Utilities.STAR) {
					i++;
					continue Torschuss;

				}

			}

			// Wird nur erreicht, wenn alle Attribute dem Attribut im
			// SchussBeispiel nicht gleichen und nicht 'egal' sind.
			alS.remove(torschuss);

		}

	}

	// # 5
	/**
	 * TODO
	 * 
	 * @param positivesBeispiel
	 * @param alG
	 * @param alNegativeBeispiele
	 */
	private static ArrayList<Torschuss> ersetzeDurchAllgemeinsteSpezialisierung(
			Torschuss positivesBeispiel, ArrayList<Torschuss> alG,
			ArrayList<Torschuss> alNegativeBeispiele) {

		Torschuss allgemeineForm = null;
		ArrayList<Torschuss> alNeueMengen = null;
		AllgemeineForm: for (int i = 0; i < alG.size();) {

			allgemeineForm = alG.get(i);
			for (Torschuss negativBeispiel : alNegativeBeispiele) {

				for (Entry<String, String> attribut : allgemeineForm
						.getAttributes().entrySet()) {
					if (istZiel(attribut))
						continue;

					// System.out.println("Vergleiche: "
					// + negativBeispiel.getAttributes().get(
					// attribut.getKey()) + " zu "
					// + attribut.getValue());

					if (!negativBeispiel.getAttributes().get(attribut.getKey())
							.equalsIgnoreCase(attribut.getValue())
							|| attribut.getValue() != Utilities.STAR) {
						i++;
						continue AllgemeineForm;

					}

				}

				// Wird nicht erreicht, wenn ein Attribut Literal aus
				// SchussBeispiel
				// nicht dem Attribut Literal aus Torschuss gleicht.
				alNeueMengen = new ArrayList<Torschuss>();
				alNeueMengen.addAll(erzeugeSpeziellsteVerallgemeinerung(
						positivesBeispiel, allgemeineForm, negativBeispiel));
				alG.remove(allgemeineForm);

			}

		}

		alG.addAll(alNeueMengen);

		return alG;
	}

	// # 6
	/**
	 * Geht alle Attribute zu jedem Torschuss durch. Wenn ein Attribut
	 * spezieller ist als das Attribut aus dem SchussBeispiel, wird der
	 * Torschuss aus der Menge G geloescht.
	 * TODO
	 * 
	 * @param besteVerallgemeinerung
	 * @param alPositiveBeispiele
	 */
	private static void streicheAlleSpezielleren(
			Torschuss besteVerallgemeinerung,
			ArrayList<Torschuss> alPositiveBeispiele) {
		/*
		 * Gehe alle Attribute zu jedem Torschuss durch. Wenn ein Attribut
		 * spezieller ist als das Attribut aus dem SchussBeispiel, wird der
		 * Torschuss aus der Menge G geloescht.
		 */

		Torschuss torschussG = null;
		String strAttributeVerallgemeinerung = null;
		String strAttributePositiv = null;

		Torschuss: for (int i = 0; i < alPositiveBeispiele.size();) {
			torschussG = alPositiveBeispiele.get(i);
			for (Entry<String, String> attribut : besteVerallgemeinerung
					.getAttributes().entrySet()) {
				if (istZiel(attribut))
					continue;

				strAttributeVerallgemeinerung = besteVerallgemeinerung
						.getAttributes().get(attribut.getKey());
				strAttributePositiv = torschussG.getAttributes().get(
						attribut.getKey());

				if (!strAttributeVerallgemeinerung
						.equalsIgnoreCase(strAttributePositiv)
						&& strAttributeVerallgemeinerung != Utilities.STAR
						&& strAttributeVerallgemeinerung != Utilities.UNDERSCORE) {

					// Kann weiter machen mit dem naechsten positiven Beispiel,
					// wenn das Beispiel und die Verallgemeinerung
					// unterschiedliche Werte haben und beide nicht '*' oder '_'
					// sind
					i++;
					continue Torschuss;

				}

			}

			alPositiveBeispiele.remove(torschussG);

		}

	}

	/**
	 * Erzeugt die speziellste Verallgemeinerung anhand der in den Parameter
	 * übergebenen Beispielen.
	 * TODO
	 * 
	 * @param positivesBeispiel
	 * @param allgemeinerTorschuss
	 * @param negativesBeispiel
	 * @return
	 */
	@SuppressWarnings("unchecked")
	private static ArrayList<Torschuss> erzeugeSpeziellsteVerallgemeinerung(
			Torschuss positivesBeispiel, Torschuss allgemeinerTorschuss,
			Torschuss negativesBeispiel) {
		ArrayList<Torschuss> alSpezielleVerallgemeinerungen = new ArrayList<Torschuss>();

		// Hier sind alle Attribute entweder (jeweils allgemein, dann
		// negativBeispiel)'*' zu Literal oder Literal == Literal. Jetzt muss
		// '*' auf Literal vom positiven Beispiel gesetzt werden.
		HashMap<String, String> hmAllgemeineAttribute = null;
		Torschuss neueVerallgemeinerung = null;

		for (Entry<String, String> attribut : positivesBeispiel.getAttributes()
				.entrySet()) {
			if (istZiel(attribut))
				continue;

			if (allgemeinerTorschuss.getAttributes().get(attribut.getKey()) == Utilities.STAR) {
				// Erzeuge einen Torschuss, in dem das aktuelle Attribut vom
				// positiven Beispiel genommen wird, alle anderen Literale von
				// dem
				// allgemeinen Beispiel und sonst nur '*'

				// Kopiere allgemeines Beispiel

				hmAllgemeineAttribute = (HashMap<String, String>) allgemeinerTorschuss
						.getAttributes().clone();
				neueVerallgemeinerung = new Torschuss(hmAllgemeineAttribute);

				// Nehme aktuelles Attribut vom positiven Beispiel
				neueVerallgemeinerung.getAttributes().put(attribut.getKey(),
						attribut.getValue());

				// Nehme speziellere Verallgemeinerung in Ergebnismenge auf
				alSpezielleVerallgemeinerungen.add(neueVerallgemeinerung);

			}

		}

		return alSpezielleVerallgemeinerungen;

	}

	/**
	 * Prüft ob ein entry das Ziel-Attribut eines Torschusses ist.
	 * 
	 * @param entry
	 *            Ein Entry<String, String> welcher aus einer HashMap kommt.
	 * @return Ob es sich bei dem Entry um eine Ziel-Definition für einen
	 *         Torschuss handelt oder nicht.
	 */
	private static boolean istZiel(Entry<String, String> entry) {
		return entry.getKey().equalsIgnoreCase(Utilities.ATTRIBUT_ZIEL);
	}

	/*
	 * (defun generalised (x y) (cond ((and (null x) (null y)) nil) <- for
	 * schleife ((equal (car x) (car y)) <- übereinstimmung (cons (car x)
	 * (generalised (cdr x) (cdr y)))) ((equal (car x) "_") (cons (car y)
	 * (generalised (cdr x)(cdr y)))) ((equal (car y) "_") (cons (car x)
	 * (generalised (cdr x)(cdr y)))) (T (cons "*" (generalised (cdr x)(cdr
	 * y))))))
	 */

	// private static void generalisieren(Ergebnis ergebnis,
	// Torschuss schussBeispiel) {
	//
	// HashMap<String, String> hmObereGrenze = ergebnis.getObereGrenze()
	// .getAttributes();
	// String strErgebnisAttributsWert = null;
	//
	// for (Entry<String, String> enAttribut : schussBeispiel.getAttributes()
	// .entrySet()) {
	//
	// // Lasse Attribut Ziel aus
	// if (enAttribut.getKey().equalsIgnoreCase(Utilities.ATTRIBUT_ZIEL))
	// continue;
	//
	// strErgebnisAttributsWert = hmObereGrenze.get(enAttribut.getKey());
	//
	// if (strErgebnisAttributsWert
	// .equalsIgnoreCase(enAttribut.getValue())) {
	// // Werte sind gleich
	// // Do nothing!
	//
	// } else if (strErgebnisAttributsWert
	// .equalsIgnoreCase(Utilities.UNDERSCORE)) {
	// // Wert auf Zettel ist noch nicht gesetzt
	// // setze Attribut in ergebnis auf wert von attribut aus
	// // schussbeispiel
	// hmObereGrenze.put(enAttribut.getKey(), enAttribut.getValue());
	//
	// } else if (strErgebnisAttributsWert
	// .equalsIgnoreCase(Utilities.STAR)) {
	// // Wert auf Zettel ist noch egal
	// // currently: do nothing!
	//
	// } else {
	// // Wert in ergebnis (ungleich 'egal') ist ungleich zu wert in
	// // schussbeispiel
	// // Verallgemeinere Attributwert in ergebnis auf 'egal'
	// hmObereGrenze.put(enAttribut.getKey(), Utilities.STAR);
	//
	// }
	//
	// }
	//
	// return;
	//
	// }

	/*
	 * (defun specialize (g neg s) (cond ((null g) nil=) ((equal (car g) "*")
	 * (cond ((equal (car neg)(car s)) (cons "*" (specialize (cdr g)(cdr
	 * neg)(cdr s)))) (T (cons (car s)(cdr g))) ) ) ((not (equal (car g)(car
	 * neg))) g) (T (cons (car g)(specialize (cdr g)(cdr neg)(cdr s)))) ) )
	 */

	// private static void spezialisieren(Ergebnis ergebnis,
	// Torschuss schussBeispiel) {
	// return;
	// }
}
